home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
ntp_src
/
ntp_pccl.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-03
|
6KB
|
242 lines
/* $Header: ntp_pcclock.c,v 1.5 91/06/21 15:21:40 ath Exp $ */
/*
* ntp_pcclock.c - routines for reading and adjusting NOS' ntp clock.
*/
#include <stdio.h>
#include "global.h"
#include "sockaddr.h"
#include "timer.h"
#include "ntp_types.h"
#include "ntp_syslog.h"
#include "ntp_fp.h"
#define CLOCK_ADJ 4
extern int debug;
/*
* These routines (init_systime, get_systime, step_systime, adj_systime)
* implement an interface between the (more or less) system independent
* bits of NTP and the hacked NOS clock. NOS now keeps time in NTP format,
* so this interface is much simpler than the Unix version.
*/
/*
* Clock variables. We limit the adjustment to (tsf_maxslew fractional sec)
* in one four second period. As we are thus limited in the speed and
* precision with which we can adjust the
* clock, we compensate by keeping the known "error" in the system time
* in sys_offset. This is added to timestamps returned by get_systime().
*/
unsigned long tsf_maxslew; /* same as above, as long format */
static l_fp sys_offset; /* correction for current system time */
/*
* init_systime - initialize the system clock support code, return
* clock precision.
*
* used in the same manner. Tick is supposed to be the number of
* microseconds which are added to the system clock at clock interrupt
* time when the time isn't being slewed. Tickadj is supposed to be
* the number of microseconds which are added or subtracted from tick when
* the time is being slewed.
*
* If either of these two variables is missing, or is there but is used
* for a purpose different than that described, you are SOL and may have
* to do some custom kludging.
*
* This really shouldn't be in here.
*/
void
init_systime()
{
u_long tickadj;
u_long tick;
u_long hz;
/*
* Obtain the values. There are both in NTP fractional seconds.
*/
tickadj = get_tickadj();
tick = get_tick();
/*
* Estimate hz from tick. I'm cheating--since tick is an NTP fraction,
* this should be 0x100000000 / tick, but we can only do 32 bit math.
*/
hz = 0xffffffffL / tick;
/*
* Set the maximum slew based on tickadj and tick. Note
* that maxslew is set slightly shorter than it needs to be as
* insurance that all slews requested will complete in CLOCK_ADJ
* seconds.
*/
tsf_maxslew = tickadj * (hz - 1) * CLOCK_ADJ;
#ifdef DEBUG
if (debug)
printf("tsf_maxslew = 0.%08lx\n", tsf_maxslew);
#endif
/*
* Set the current offset to 0
*/
sys_offset.l_ui = sys_offset.l_uf = 0;
}
/*
* get_systime - return the system time in timestamp format
*/
void
get_systime(ts)
l_fp *ts;
{
#ifndef SLEWALWAYS
/*
* Quickly get the time of day.
*/
getntptimeofday (ts);
#else /* SLEWALWAYS */
/*
* Get the time of day and add in the current time offset.
* Then round appropriately.
*/
getntptimeofday (ts);
L_ADD(ts, &sys_offset);
#endif /* SLEWALWAYS */
}
/*
* step_systime - do a step adjustment in the system time (at least from
* NTP's point of view.
*/
void
step_systime(ts)
l_fp *ts;
{
#ifndef SLEWALWAYS
extern char *lfptoa();
extern void stepntptime ();
/*
* We can afford to be sloppy here since if this is called
* the time is really screwed and everything is being reset.
*/
L_ADD(&sys_offset, ts);
/* call the hardware-specific step routine. */
stepntptime (&sys_offset);
#ifdef DEBUG
if (debug > 3)
printf("step: %s, sys_offset = %s\n",
lfptoa(&ts, 9), lfptoa(&sys_offset, 9));
#endif
sys_offset.l_ui = sys_offset.l_uf = 0;
#else
/*
* Just add adjustment into the current offset. The update
* routine will take care of bringing the system clock into
* line.
*/
L_ADD(&sys_offset, ts);
#endif /* SLEWALWAYS */
}
/*
* adj_systime - called once every CLOCK_ADJ seconds to make system time
* adjustments.
*/
void
adj_systime(adj)
long adj;
{
register unsigned long offset_i, offset_f;
int32 slew, leftover;
register int isneg = 0;
extern char *mfptoa();
extern char *umfptoa();
/*
* Move the current offset into the registers
*/
offset_i = sys_offset.l_ui;
offset_f = sys_offset.l_uf;
/*
* Add the new adjustment into the system offset. Adjust the
* system clock to minimize this.
*/
M_ADDF(offset_i, offset_f, adj);
if (M_ISNEG(offset_i, offset_f)) {
isneg = 1;
M_NEG(offset_i, offset_f);
}
#ifdef DEBUG
if (debug > 4)
printf("adj_systime(%s): offset = %s%s\n",
mfptoa((adj<0?-1L:0L), adj, 9), isneg?"-":"",
umfptoa(offset_i, offset_f, 9));
#endif
if (offset_i > 0 || offset_f >= tsf_maxslew) {
/*
* Slew is bigger than we can complete in
* the adjustment interval. Make a maximum
* sized slew and reduce sys_offset by this
* much.
*/
M_SUBUF(offset_i, offset_f, tsf_maxslew);
if (!isneg) {
slew = tsf_maxslew;
} else {
slew = -tsf_maxslew;
M_NEG(offset_i, offset_f);
}
#ifdef DEBUG
if (debug > 4)
printf(
"maximum slew: %s%s, remainder = %s\n",
isneg?"-":"", umfptoa(0L, tsf_maxslew, 9),
mfptoa(offset_i, offset_f, 9));
#endif
} else {
/*
* We can do this slew in the time period.
*
* Note that offset_i is guaranteed to be 0 here.
*/
if (isneg) {
slew = -offset_f;
} else {
slew = offset_f;
}
offset_i = offset_f = 0;
#ifdef DEBUG
if (debug > 4)
printf("slew: %s\n", mfptoa((slew<0?-1L:0L), slew, 9));
#endif
}
sys_offset.l_ui = offset_i;
sys_offset.l_uf = offset_f;
if (slew == 0)
return;
if (leftover = adjtime (slew)) {
syslog(LOG_ERR, "Previous time adjustment didn't complete");
#ifdef DEBUG
if (debug > 4)
printf(
"Previous adjtime() incomplete, residual = %ld\n",
leftover);
#endif
}
}